package net.cjw.initsb.aop;

import java.lang.reflect.Method;
import java.util.Date;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import net.cjw.initsb.entity.QuartzTaskLog;
import net.cjw.initsb.service.QuartzTaskLogServiceI;

@Aspect
@Component
public class QuartzInterceptor {

	@Autowired
	private QuartzTaskLogServiceI quartzTaskLogServiceI;

	Logger logger = LoggerFactory.getLogger(this.getClass());
	// 使用@Aspect注解将一个java类定义为切面类
	// 使用@Pointcut定义一个切入点，可以是一个规则表达式，比如下例中某个package下的所有函数，也可以是一个注解等。
	// 根据需要在切入点不同位置的切入内容
	// 使用@Before在切入点开始处切入内容
	// 使用@After在切入点结尾处切入内容
	// 使用@AfterReturning在切入点return内容之后切入内容（可以用来对处理返回值做一些加工处理）
	// 使用@Around在切入点前后切入内容，并自己控制何时执行切入点自身的内容
	// 使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑

	@Pointcut("execution(public * net.cjw.initsb.config.quartz.task.*.*(..))")
	public void pointcut() {
		// logger.info("QuartzInterceptor: pointcut()");
	}

	@Before("pointcut()")
	public void before(JoinPoint joinPoint) {
		// logger.info("QuartzInterceptor: before()");
	}

	@After("pointcut()")
	public void after(JoinPoint joinPoint) {
		// logger.info("QuartzInterceptor: after()");
	}

	@AfterReturning("pointcut()")
	public void afterReturning(JoinPoint joinPoint) {
		// 虽然AfterReturning增强处理可以访问到目标方法的返回值，但它不可以改变目标方法的返回值。
		// logger.info("QuartzInterceptor: afterReturning()");
	}

	@AfterThrowing("pointcut()")
	public void afterThrowing(JoinPoint joinPoint) {
		/*
		 * AOP的AfterThrowing处理虽然可以对目标方法的异常进行处理，但这种处理与直接使用catch捕捉不同，
		 * catch捕捉意味着完全处理该异常，如果catch块中没有重新抛出新的异常，则该方法可能正常结束；
		 * 而AfterThrowing处理虽然处理了该异常，但它不能完全处理异常，该异常依然会传播到上一级调用者，即JVM。
		 */
		// logger.info("QuartzInterceptor: afterThrowing()");
	}

	@Around("pointcut()")
	public Object around(ProceedingJoinPoint pjp) {
		// logger.info("QuartzInterceptor: around()");

		// 获取方法名
		Signature s = pjp.getSignature();
		MethodSignature ms = (MethodSignature) s;
		Method m = ms.getMethod();
		String methodName = m.getName();
		// 接口执行前
		Long startTime = System.currentTimeMillis();
		Object rs = null;
		try {
			rs = pjp.proceed();// 继续执行其他aop拦截处理
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Long endTime = System.currentTimeMillis();
		Long executeSecond = (endTime - startTime) / 1000;
		QuartzTaskLog entity = new QuartzTaskLog();
		entity.setEndTime(new Date(endTime));
		entity.setStartTime(new Date(startTime));
		entity.setExecuteSecond(executeSecond);
		entity.setMethodName(methodName);

		quartzTaskLogServiceI.create(entity);
		return rs;
	}
	// 执行结果
	// 2017-11-25 21:34:30.003 INFO 290272 --- [eduler_Worker-7]
	// net.cjw.initsb.aop.QuartzInterceptor : QuartzInterceptor: around()
	// 2017-11-25 21:34:30.003 INFO 290272 --- [eduler_Worker-7]
	// net.cjw.initsb.aop.QuartzInterceptor : QuartzInterceptor: before()
	// 2017-11-25 21:34:30.003 INFO 290272 --- [eduler_Worker-7]
	// uleTask$$EnhancerBySpringCGLIB$$85a141a6 : 我是定时任务一的方法
	// 2017-11-25 21:34:30.003 INFO 290272 --- [eduler_Worker-7]
	// net.cjw.initsb.aop.QuartzInterceptor : QuartzInterceptor: after()
	// 2017-11-25 21:34:30.003 INFO 290272 --- [eduler_Worker-7]
	// net.cjw.initsb.aop.QuartzInterceptor : QuartzInterceptor: afterReturning()

}
